import re
import os

commonInstruct = r"^\s+\w+:\s+(\w+)"
splitLine = r"^\s+\w+:\s+(\w+)\s+(.*)"

content_r = "op: {opcode}, func3: {func3}, func7: {func7}, rd: {rd}, rs1: {rs1}, rs2: {rs2}\n"
content_sb = "op: {opcode}, func3: {func3}, rs1: {rs1}, rs2: {rs2}, imm: {imm}\n"
content_i = "op: {opcode}, func3: {func3}, rd: {rd}, rs1: {rs1}, imm: {imm}\n"
content_uj = "op: {opcode}, rd: {rd}, imm: {imm}\n"


# 注意python数组下标从-1开始数!!!!

def hexstr_to_bistr(hexstr, fill=32):
    return bin(int(hexstr, 16))[2:].zfill(fill)


def separate_as_r32(code):
    code = hexstr_to_bistr(code)
    ret = {'func7': code[-32: -25],
           'rs2': code[-25: -20],
           'rs1': code[-20: -15],
           'rd': code[-12: -7],
           'opcode': code[-7:],
           'func3': code[-15: -12]}
    return ret


def separate_as_i32(code):
    code = hexstr_to_bistr(code)
    ret = {'imm': code[-32: -20],
           'rs2': code[-25: -20],
           'rs1': code[-20: -15],
           'rd': code[-12: -7],
           'opcode': code[-7:],
           'func3': code[-15: -12]}
    return ret


def separate_as_s32(code):
    code = hexstr_to_bistr(code)
    ret = {'imm': code[-32: -25] + code[-12: -7],
           'rs2': code[-25: -20],
           'rs1': code[-20: -15],
           'rd': code[-12: -7],
           'opcode': code[-7:],
           'func3': code[-15: -12]}
    return ret


def separate_as_b32(code):
    code = hexstr_to_bistr(code)
    ret = {'imm': code[-32] + code[-8] + code[-31:-25] + code[-12:-8],
           'rs2': code[-25: -20],
           'rs1': code[-20: -15],
           'rd': code[-12: -7],
           'opcode': code[-7:],
           'func3': code[-15: -12]}
    return ret


def separate_as_u32(code):
    code = hexstr_to_bistr(code)
    ret = {'imm': code[-32: -12],
           'rs2': code[-25: -20],
           'rs1': code[-20: -15],
           'rd': code[-12: -7],
           'opcode': code[-7:],
           'func3': code[-15: -12]}
    return ret


def separate_as_j32(code):
    code = hexstr_to_bistr(code)
    ret = {'imm': code[-32] + code[-20: -12] + code[-21] + code[-31:-21],
           'rs2': code[-25: -20],
           'rs1': code[-20: -15],
           'rd': code[-12: -7],
           'opcode': code[-7:],
           'func3': code[-15: -12]}
    return ret


def match_exact(line, outlines: list):
    match = re.match(splitLine, line)
    if match is None:
        return
    hex_code = match.group(1)
    ins = match.group(2)

    # save - load指令 * 4
    sw = r"sw\s+(\w+),(-?\d+)\((\w+)\)"
    m = re.match(sw, ins)
    if m is not None:
        sep = separate_as_s32(hex_code)
        outlines.append(content_sb.format(**sep))
        outlines.append(f"sw指令: M[{m.group(3)} + ({m.group(2)})][0:31] = {m.group(1)}[0:31]\n")
        return

    sd = r"sd\s+(\w+),(-?\d+)\((\w+)\)"
    m = re.match(sd, ins)
    if m is not None:
        sep = separate_as_s32(hex_code)
        outlines.append(content_sb.format(**sep))
        outlines.append(f"sd指令: M[{m.group(3)} + ({m.group(2)})][0:63] = {m.group(1)}[0:63]\n")
        return

    lw = r"lw\s+(\w+),(-?\d+)\((\w+)\)"
    m = re.match(lw, ins)
    if m is not None:
        sep = separate_as_i32(hex_code)
        outlines.append(content_i.format(**sep))
        outlines.append(f"lw指令: {m.group(1)} = M[{m.group(3)} + ({m.group(2)})][0:31]\n")
        return

    ld = r"ld\s+(\w+),(-?\d+)\((\w+)\)"
    m = re.match(ld, ins)
    if m is not None:
        sep = separate_as_i32(hex_code)
        outlines.append(content_i.format(**sep))
        outlines.append(f"ld指令: {m.group(1)} = M[{m.group(3)} + ({m.group(2)})][0:63]\n")
        return

    # i型指令
    sextw = r"sext.w\s+(\w+),(\w+)"
    m = re.match(sextw, ins)
    if m is not None:
        sep = separate_as_i32(hex_code)
        outlines.append(content_i.format(**sep))
        outlines.append(f"sext.w(addiw)指令: {m.group(1)}[0:31] = {m.group(2)} + 0\n")
        return

    li = r"li\s+(\w+),(-?\d+)"
    m = re.match(li, ins)
    if m is not None:
        sep = separate_as_i32(hex_code)
        outlines.append(content_i.format(**sep))
        outlines.append(f"li指令: {m.group(1)} = {m.group(2)}\n")
        return

    mv = r"mv\s+(\w+),(\w+)"
    m = re.match(mv, ins)
    if m is not None:
        sep = separate_as_i32(hex_code)
        outlines.append(content_i.format(**sep))
        outlines.append(f"mv(addi)指令: {m.group(1)}[0:31] = {m.group(2)} + 0\n")
        return

    addi = r"addi\s+(\w+),(\w+),(-?\d+)"
    m = re.match(addi, ins)
    if m is not None:
        sep = separate_as_i32(hex_code)
        outlines.append(content_i.format(**sep))
        outlines.append(f"addi指令: {m.group(1)} = {m.group(2)} + {m.group(3)}\n")
        return

    addiw = r"addiw\s+(\w+),(\w+),(-?\d+)"
    m = re.match(addiw, ins)
    if m is not None:
        sep = separate_as_i32(hex_code)
        outlines.append(content_i.format(**sep))
        outlines.append(f"addiw指令: {m.group(1)}[0:31] = {m.group(2)} + {m.group(3)}\n")
        return

    andi = r"andi\s+(\w+),(\w+),(-?\d+)"
    m = re.match(andi, ins)
    if m is not None:
        sep = separate_as_i32(hex_code)
        outlines.append(content_i.format(**sep))
        outlines.append(f"andi指令: {m.group(1)} = {m.group(2)} & {m.group(3)}\n")
        return
    
    srliw = r"srliw\s+(\w+),(\w+),(\w+)"
    m = re.match(srliw, ins)
    if m is not None:
        sep = separate_as_i32(hex_code)
        outlines.append(content_i.format(**sep))
        outlines.append(f"srliw指令: {m.group(1)}[0:31] = {m.group(2)} >> {m.group(3)}\n")
        return

    slliw = r"slliw\s+(\w+),(\w+),(\w+)"
    m = re.match(slliw, ins)
    if m is not None:
        sep = separate_as_i32(hex_code)
        outlines.append(content_i.format(**sep))
        outlines.append(f"slliw指令: {m.group(1)}[0:31] = {m.group(2)} << {m.group(3)}\n")
        return

    # R型指令
    mulw = r"mulw\s+(\w+),(\w+),(\w+)"
    m = re.match(mulw, ins)
    if m is not None:
        sep = separate_as_r32(hex_code)
        outlines.append(content_r.format(**sep))
        outlines.append(f"mulw指令: {m.group(1)}[0:31] = {m.group(2)} * {m.group(3)}\n")
        return

    addw = r"addw\s+(\w+),(\w+),(\w+)"
    m = re.match(addw, ins)
    if m is not None:
        sep = separate_as_r32(hex_code)
        outlines.append(content_r.format(**sep))
        outlines.append(f"addw指令: {m.group(1)}[0:31] = {m.group(2)} + {m.group(3)}\n")
        return
    
    # U型指令
    auipc = r"auipc\s+(\w+),(\w+)"
    m = re.match(auipc, ins)
    if m is not None:
        sep = separate_as_u32(hex_code)
        outlines.append(content_uj.format(**sep))
        outlines.append(f"auipc指令: {m.group(1)} = PC + ({m.group(2)} << 12)\n")
        return

    # J型指令
    jalr = r"ret"
    m = re.match(jalr, ins)
    if m is not None:
        sep = separate_as_i32(hex_code)
        outlines.append(content_i.format(**sep))
        outlines.append(f"ret(jalr)指令: jalr zero, ra, 0\n")
        return

    jalr = r"jalr\s+(\w+)\s+#\s+(\w+)\s+(.+)" # 这个是I型
    m = re.match(jalr, ins)
    if m is not None:
        sep = separate_as_i32(hex_code)
        outlines.append(content_i.format(**sep))
        outlines.append(f"jalr指令: {m.group(1)} = PC + 4; PC += {m.group(2)}, 即跳转至{m.group(3)}处\n")
        return

    j = r"j\s+(\w+)\s+(.+)"
    m = re.match(j, ins)
    if m is not None:
        sep = separate_as_j32(hex_code)
        outlines.append(content_uj.format(**sep))
        outlines.append(f"j(jal)指令: x0 = PC + 4; PC += {m.group(1)}, 即跳转至{m.group(2)}处\n")
        return
    
    # B型指令
    bge = r"bge\s+(\w+),(\w+),(\w+)\s+(.+)"
    m = re.match(bge, ins)
    if m is not None:
        sep = separate_as_b32(hex_code)
        outlines.append(content_sb.format(**sep))
        outlines.append(f"bge指令: if({m.group(1)} >= {m.group(2)}) PC += {m.group(3)}, 即跳转至{m.group(4)}处\n")
        return

    # 输出文件
    with open('rest.txt', 'a+') as f:
        f.write(line)


def auto(path):
    try:
        os.remove('rest.txt')
    except FileNotFoundError:
        pass
    with open(path, 'r') as f:
        lines = f.readlines()
    outlines = []
    for line in lines:
        # outlines.append(line)
        match = re.match(commonInstruct, line)
        if match is None:
            outlines.append(line)
        else:
            # print(line, end='')
            print(match.group(1))
            outlines.append(line[2:])
            bi = [hexstr_to_bistr(c, 4) for c in match.group(1)]
            bi = ' '.join(bi)
            outlines.append(f"{match.group(1)}: 二进制为{bi}\n")
            match_exact(line, outlines)
        outlines.append('\n')
    with open('a' + path, 'w') as f:
        f.writelines(outlines)


if __name__ == '__main__':
    auto('pytest2.txt')  # 反汇编源文件
